/*
 * Copyright 2012 Finbudget.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package finbudgettable.client.ui.grid.cell.suggest;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Document;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.user.client.ui.SuggestOracle;
import com.google.gwt.user.client.ui.ValueBoxBase;

import finbudget.client.general.NodeSuggestionOracle;
import finbudget.client.lists.GetListOfItems.BudgetListItem;
import finbudget.client.ui.input.widgets.SuggestBoxEx;
import finbudgettable.client.ui.grid.cell.AbstractPopupEditor;
import finbudgettable.client.ui.grid.event.ValueChangedEvent;

public class SuggestCellEditor extends AbstractPopupEditor<String> {

    private final boolean nullable;
//    private final SuggestDropdownBox suggestBox;
    private final SuggestBoxEx suggestBox;
    private final NodeSuggestionOracle oracle;

    @Override
    public void setValue(String key) {
        suggestBox.setValue(oracle.getItemNameByKey(key));
    }

    public SuggestCellEditor(boolean nullable, NodeSuggestionOracle oracle) {
        super();
        this.nullable = nullable;
        this.oracle = oracle;
        setStyleName("");

//        suggestBox = new SuggestDropdownBox(oracle);
        suggestBox = new SuggestBoxEx(oracle);
        suggestBox.setStylesForTable();
        suggestBox.addSelectionHandler(new SelectionHandler<SuggestOracle.Suggestion>() {
            @Override
            public void onSelection(SelectionEvent<SuggestOracle.Suggestion> event) {
                String value = event.getSelectedItem().getReplacementString();
                fireEvent(new ValueChangedEvent<String>(getKeyByValue(value)));
                hide();
            }
        });
        suggestBox.getTextBox().addKeyDownHandler(new KeyDownHandler() {
            @Override
            public void onKeyDown(final KeyDownEvent event) {
                int keyCode = event.getNativeKeyCode();
                if (keyCode == KeyCodes.KEY_RIGHT || keyCode == KeyCodes.KEY_END) {
                    ValueBoxBase<String> textBox = suggestBox.getTextBox();
                    int cursorPos = textBox.getCursorPos();
                    boolean cursorInLastPos = textBox.getValue().length() == cursorPos;
                    if (cursorInLastPos) {
                        //suggestDisplay.hideSuggestions();
                        hide();
                        event.preventDefault();
                        repeatKeyDownEvent(keyCode);
                    }
                } else if (keyCode == KeyCodes.KEY_LEFT || keyCode == KeyCodes.KEY_HOME) {
                    ValueBoxBase<String> textBox = suggestBox.getTextBox();
                    int cursorPos = textBox.getCursorPos();
                    boolean cursorInFirstPos = cursorPos == 0;
                    if (cursorInFirstPos) {
                        //suggestDisplay.hideSuggestions();
                        hide();
                        event.preventDefault();
                        repeatKeyDownEvent(keyCode);
                    }
                } else if (keyCode == KeyCodes.KEY_ENTER) {
                	// Get value of text box as it could contain not a complete sentence
                    String value = suggestBox.getTextBox().getValue();
                    if (hasKey(value) || (SuggestCellEditor.this.nullable && (value == null || value.isEmpty()))) {
                        fireEvent(new ValueChangedEvent<String>(suggestBox.getValue()));
                        hide();
                    }
                }
            }
        });
        suggestBox.addKeyUpHandler(new KeyUpHandler() {
            @Override
            public void onKeyUp(KeyUpEvent event) {
                int keyCode = event.getNativeKeyCode();
                if (keyCode == KeyCodes.KEY_ESCAPE) {
                    //suggestDisplay.hideSuggestions();
                    hide();
                }
            }
        });
        add(suggestBox);
    }

    private String getKeyByValue(String value) {
    	BudgetListItem item = SuggestCellEditor.this.oracle.getItemByValue(value); 
        return item == null ? null : item.key;
    }

    private boolean hasKey(String value) {
        return oracle.getItemByValue(value) != null;
    }

    private void repeatKeyDownEvent(final int keyCode) {
        Scheduler.get().scheduleFinally(new Scheduler.ScheduledCommand() {
            @Override
            public void execute() {
                getLastParent().dispatchEvent(Document.get().createKeyDownEvent(false, false, false, false, keyCode));
            }
        });
    }

    @Override
    public void setVisible(boolean visible) {
        super.setVisible(visible);
        if (visible) {
            suggestBox.setFocus(true);
        }
    }

    public void setSuggestBoxHeight(String height) {
//        GWT.log("height: " + height);
//        suggestBox.setHeight(Integer.parseInt(height.replace("px", "")));
    	suggestBox.setHeight(height);
    }

    public void setSuggestBoxWidth(String width) {
//        suggestBox.setWidth(Integer.parseInt(width.replace("px", "")));
    	suggestBox.setWidth(width);
    }

    public int getSuggestBoxLeftOffset() {
        return suggestBox.getAbsoluteLeft() - getAbsoluteLeft();
    }

    public int getSuggestBoxTopOffset() {
        return suggestBox.getAbsoluteTop() - getAbsoluteTop();
    }

	@Override
	public void proceedSettingReadonly() {
		suggestBox.setEnabled(!isReadonly());
	}

	@Override
	public void hide() {
		suggestBox.hideSuggestions();
		super.hide();
	}
}
